import StringUtils from '@/utils/StringUtils';
import { useCallback, useEffect, useRef, useState } from 'react';
// import {type EventSubscription} from 'react-native';
import BleManager, {
  BleState,
  Characteristic,
  PeripheralInfo,
  type Peripheral,
} from 'react-native-ble-manager';
import { Buffer } from 'buffer';
import {
  PermissionsAndroid,
  Permission,
  Platform,
  EventSubscription,
} from 'react-native';
import ArrayUtils from '@/utils/ArrayUtils';
import PermissionUtils, { PERMISSIONS } from '@/utils/PermissionUtils';
// type EventNames = 'onDiscoverPeripheral';
BleManager.start({
  showAlert: true,
}).then(() => {
  console.log('Module initialized');
});
function uniquePeripheralsArray(peripheralsArray: Peripheral[]) {
  return peripheralsArray.filter(
    (peripheral, index) => peripheralsArray.indexOf(peripheral) === index
  );
}

/**
 * 将十进制的长度转换为16进制的字节数组
 */
function decimalToHexByteArray(length: number): number[] {
  if (length < 0 || length > 0xffff) {
    throw new Error('Length must be between 0 and 65535');
  }

  // 转换为16进制字符串，并补齐4位(2字节)
  let hexStr = length.toString(16).toUpperCase();
  while (hexStr.length < 4) {
    hexStr = '0' + hexStr;
  }

  return Buffer.from(hexStr, 'hex').toJSON().data as number[];
}
/**
 * 将16进制的字节数组转换为十进制的长度
 */
function hexByteArrayToDecimal(hexByteArray: number[]): number {
  if (hexByteArray.length !== 2) {
    throw new Error('Input must be a 2-byte array');
  }
  const hexStr = Buffer.from(hexByteArray).toString('hex');

  return parseInt(hexStr, 16);
}

// type BleCharacteristics = {
//   write: string;
//   notify: string;
// };

// const KNOWN_BLE_CHARACTERISTICS: BleCharacteristics[] = [
//   {
//     /// 腾圣
//     write: 'FED7',
//     notify: 'FED8',
//   },
//   {
//     /// 普兆
//     write: '0000FED7-0000-1000-8000-00805F9B34FB',
//     notify: '0000FED8-0000-1000-8000-00805F9B34FB',
//   },
// ];

const useBleScan = () => {
  const [isScanning, setIsScanning] = useState(false);
  const [peripherals, setPeripherals] = useState<Peripheral[]>([]);
  const onDidUpdateValueForCharacteristicSubscription =
    useRef<EventSubscription>(null);
  const connectedPeripheral = useRef<PeripheralInfo>(null);
  const connecting = useRef<boolean>(false);
  const [bluetoothDialogShouldOpen, setBluetoothDialogShouldOpen] =
    useState(false);
  /// 连接到蓝牙后，保存用于写入和读取的特征值
  const characteristicForWrite = useRef<Characteristic>(null);
  const characteristicForNotify = useRef<Characteristic>(null);
  const receivedContents = useRef<number[]>(null);
  const contentLengthShouldReceive = useRef<number>(null);
  const maxByteCountOneTime = useRef<number>(20);
  const [permissionDialogShouldOpen, setPermissionDialogShouldOpen] =
    useState(false);

  useEffect(() => {
    const onNewDeviceDetected = BleManager.onDiscoverPeripheral(
      (peripheral: Peripheral) => {
        if (!peripheral.advertising.isConnectable) {
          return;
        }
        const deviceName =
          peripheral.name || peripheral.advertising.localName || peripheral.id;
        if (!deviceName) {
          return;
        }
        const regex = /^[A-Za-z0-9]+$/;
        if (!regex.test(deviceName)) {
          return;
        }
        setPeripherals((prev) => {
          const existsIndex = prev.findIndex((i) => i.id === peripheral.id);
          if (existsIndex === -1) {
            return [...prev, peripheral];
          }
          return prev;
        });
      }
    );

    const onStopScan = BleManager.onStopScan(() => {
      setIsScanning(false);
    });

    return () => {
      if (connectedPeripheral.current) {
        BleManager.disconnect(connectedPeripheral.current.id);
      }
      if (isScanning) {
        BleManager.stopScan();
      }
      onNewDeviceDetected.remove();
      onStopScan.remove();
      onDidUpdateValueForCharacteristicSubscription.current?.remove();
      if (connectedPeripheral.current && characteristicForNotify.current) {
        BleManager.stopNotification(
          connectedPeripheral.current.id,
          characteristicForNotify.current.service,
          characteristicForNotify.current.characteristic
        );
      }
    };
  }, [connectedPeripheral]);

  const ensureBluetoothEnabled = useCallback(async () => {
    const status = await BleManager.checkState();
    if (status === BleState.Off) {
      if (Platform.OS === 'android') {
        await BleManager.enableBluetooth();
      } else {
        setBluetoothDialogShouldOpen(true);
      }
    }
  }, []);

  const checkBluetoothPermissions = useCallback(async () => {
    return await requestBluetoothPermissions();
  }, []);

  const startScan = useCallback(
    async (...options: Parameters<typeof BleManager.scan>) => {
      const havePermission = await checkBluetoothPermissions();
      if (!havePermission) {
        setPermissionDialogShouldOpen(true);
        return;
      } else {
        setPermissionDialogShouldOpen(false);
      }
      await ensureBluetoothEnabled();
      setIsScanning(true);
      BleManager.scan(...options)
        .then(() => {
          console.log('开始扫描周边蓝牙设备');
        })
        .catch((reason) => {
          console.log('扫描蓝牙设备失败', reason);
        });
    },
    []
  );
  const stopScan = useCallback(async () => {
    BleManager.stopScan()
      .then(() => {
        console.log('设备扫描结束');
        return true;
      })
      .catch((reason) => false);
  }, []);
  const getDiscoveredPeripherals = () => {
    BleManager.getDiscoveredPeripherals().then((peripheralsArray) => {
      // Handle the discovered peripherals
      const result = uniquePeripheralsArray(peripheralsArray);
      setPeripherals(result);
      setIsScanning(false);
    });
  };

  const updateConnectedPeripheral = useCallback(
    (peripheralInfo: PeripheralInfo) => {
      connectedPeripheral.current = peripheralInfo;

      const characteristics = peripheralInfo.characteristics ?? [];
      if (ArrayUtils.isNotEmpty(characteristics)) {
        for (const characteristic of characteristics) {
          const isWrite = Boolean(
            characteristic.properties.Write ||
              characteristic.properties.WriteWithoutResponse
          );

          if (isWrite && !characteristicForWrite.current) {
            characteristicForWrite.current = characteristic;
            continue;
          }
          const isNotify = Boolean(characteristic.properties.Notify);
          if (isNotify && !characteristicForNotify.current) {
            characteristicForNotify.current = characteristic;
            continue;
          }
        }
      }
    },
    []
  );

  const connectToDevice = useCallback(
    (deviceId: string): Promise<PeripheralInfo> => {
      if (connecting.current) {
        return Promise.reject('正在连接中');
      }
      connecting.current = true;
      return BleManager.connect(deviceId, {
        autoconnect: true,
      })
        .then(() => {
          connecting.current = false;
          console.log('设备连接成功，开始获取设备详细信息', deviceId);
          return BleManager.retrieveServices(deviceId)
            .then((peripheralInfo) => {
              console.log('设备详细信息获取成功', peripheralInfo);
              if (Platform.OS === 'android') {
                return BleManager.requestMTU(deviceId, 256)
                  .then((mtu) => {
                    console.log(`MTU成功协商到${mtu}字节`);
                    maxByteCountOneTime.current = mtu;
                    updateConnectedPeripheral(peripheralInfo);
                    return peripheralInfo;
                  })
                  .catch((reason) => {
                    console.log(
                      'MTU协商失败，数据传输大小回退到20字节。',
                      reason
                    );
                    updateConnectedPeripheral(peripheralInfo);
                    return peripheralInfo;
                  });
              } else {
                /// 硬件反馈，iOS最大MTU为185
                maxByteCountOneTime.current = 185;
                updateConnectedPeripheral(peripheralInfo);
                return peripheralInfo;
              }
            })
            .catch((reason) => {
              console.log('Cannot retrieve device info', reason);
              return Promise.reject('无法获取蓝牙设备信息，连接失败');
            });
        })
        .catch((error) => {
          connecting.current = false;
          console.error('Connection error:', error);
          return Promise.reject('Connection error');
        });
    },
    [connectedPeripheral]
  );

  const requestBiggerTransferSize = useCallback(
    (size: number = 512): Promise<number> => {
      if (connectedPeripheral.current) {
        return BleManager.requestMTU(connectedPeripheral.current.id, size);
      }
      return Promise.reject('尝试协商MTU大小，但是没有已经连接的设备');
    },
    []
  );

  const write = useCallback(
    (contents: number[]): Promise<void> => {
      if (!connectedPeripheral.current) {
        return Promise.reject('Not connected');
      }
      if (contents.length === 0) {
        return Promise.reject("Contents can't be empty");
      }

      if (!characteristicForWrite.current) {
        return Promise.reject('Characteristics not found');
      }
      const isWriteWithoutResponse = Boolean(
        characteristicForWrite.current.properties.WriteWithoutResponse
      );
      const contentsLength = decimalToHexByteArray(contents.length);
      const contentsWithLength = [...contentsLength, ...contents];
      let promise: Promise<void>;
      if (isWriteWithoutResponse) {
        promise = BleManager.writeWithoutResponse(
          connectedPeripheral.current.id,
          characteristicForWrite.current.service,
          characteristicForWrite.current.characteristic,
          contentsWithLength,
          maxByteCountOneTime.current
        );
      } else {
        promise = BleManager.write(
          connectedPeripheral.current.id,
          characteristicForWrite.current.service,
          characteristicForWrite.current.characteristic,
          contentsWithLength,
          maxByteCountOneTime.current
        );
      }
      return promise
        .then(() => {
          console.log(
            `写入成功，实际内容是：${contentsWithLength}，切片长度：${maxByteCountOneTime.current}`
          );
          return Promise.resolve();
        })
        .catch((reason) => {
          console.log('写入失败', reason);
          return Promise.reject(reason);
        });
    },
    [connectedPeripheral]
  );

  const addListener = useCallback(
    async (callback: (value: number[]) => void) => {
      if (connectedPeripheral.current) {
        if (!characteristicForNotify.current) {
          return Promise.reject('No notify characteristic found');
        }
        return BleManager.startNotification(
          connectedPeripheral.current.id,
          characteristicForNotify.current.service,
          characteristicForNotify.current.characteristic
        )
          .then((v) => {
            console.log(
              '添加监听器成功，特征信息：',
              characteristicForNotify.current
            );

            onDidUpdateValueForCharacteristicSubscription.current =
              BleManager.onDidUpdateValueForCharacteristic((data: any) => {
                const value = data.value as number[];
                console.log(`收到来自设备的通知：${JSON.stringify(data)}`);
                if (value.length === 0) {
                  return;
                }
                try {
                  if (contentLengthShouldReceive.current == null) {
                    // 把value拆分成两个数组，第一个数组长度为2，第二个数组长度为value.length - 2
                    const contentLengthBytes = value.slice(0, 2);
                    const actualContents = value.slice(2);
                    contentLengthShouldReceive.current =
                      hexByteArrayToDecimal(contentLengthBytes);
                    receivedContents.current = actualContents;
                  } else {
                    if (receivedContents.current == null) {
                      receivedContents.current = value;
                    } else {
                      receivedContents.current = [
                        ...receivedContents.current,
                        ...value,
                      ];
                    }
                  }
                  if (
                    contentLengthShouldReceive.current <=
                    receivedContents.current.length
                  ) {
                    callback(receivedContents.current);
                    contentLengthShouldReceive.current = null;
                    receivedContents.current = null;
                  }
                } catch (e) {}
              });
          })
          .catch((reason) => {
            console.log('无法添加监听器', reason);
          });
      }
    },
    [connectedPeripheral]
  );

  // const read = useCallback(
  //   async (): Promise<string> => {
  //     if (!connectedPeripheral.current) {
  //       return Promise.reject('Cannot read, not connected');
  //     }
  //     if (characteristic === undefined) {
  //       return Promise.reject('Characteristics not found');
  //     }

  //     try {
  //       const result = await BleManager.read(
  //         connectedPeripheral.current.id,
  //         characteristic.service,
  //         characteristicUUID
  //       );
  //       const buffer = Buffer.from(result);
  //       return buffer.toString('utf-8');
  //     } catch (e) {
  //       throw e;
  //     }
  //   },
  //   [connectedPeripheral]
  // );

  return {
    peripherals,
    startScan,
    stopScan,
    connectToDevice,
    // read,
    write,
    connectedPeripheral,
    isScanning,
    addListener,
    bluetoothDialogShouldOpen,
    setBluetoothDialogShouldOpen,
    permissionDialogShouldOpen,
    setPermissionDialogShouldOpen,
  };
};
export default useBleScan;

async function requestBluetoothPermissions() {
  if (Platform.OS === 'android') {
    // const permissions: Permission[] = [];
    // if (Platform.Version >= 23 && Platform.Version <= 30) {
    //   permissions.push(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION);
    // } else if (Platform.Version >= 31) {
    //   permissions.push(
    //     PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
    //     PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
    //     PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION
    //   );
    // }

    // if (permissions.length === 0) {
    //   return true;
    // }
    // const granted = await PermissionsAndroid.requestMultiple(permissions);
    // return Object.values(granted).every(
    //   (result) => result === PermissionsAndroid.RESULTS.GRANTED
    // );
    const status = await PermissionUtils.checkMultiplePermissions([
      PERMISSIONS.ANDROID.BLUETOOTH_SCAN,
      PERMISSIONS.ANDROID.BLUETOOTH_CONNECT,
      PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION,
    ]);
    if (
      status[PERMISSIONS.ANDROID.BLUETOOTH_SCAN].granted &&
      status[PERMISSIONS.ANDROID.BLUETOOTH_CONNECT].granted &&
      status[PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION].granted
    ) {
      return true;
    }
    return false;
  }
  return true;
}
